# 基础参数
import hashlib
import math

from pydantic import BaseModel
from typing import List, Dict

class CasingParams(BaseModel):
    # 开始深度
    start: float
    # 结束深度
    end: float
    # 套管内径
    d: float
    # 下放摩擦系数
    mu_pull: float
    # 上提摩擦系数
    mu_push: float

class StabilityParams(BaseModel):
    # 将原来的深度改为开始的深度和结束深度
    # 开始深度
    start_depth: float
    # 结束深度
    end_depth: float
    # 岩石内聚力
    cohesion: float
    # 岩石内摩擦角
    internal_friction_angle: float
    # 地层应力系数
    formation_stress_factor: float
    # 泊松比
    poisson_ratio: float
    # 最大水平地应力梯度
    max_horizontal_ground_stress_gradient: float
    # 最小水平地应力梯度
    min_horizontal_ground_stress_gradient: float
    # 垂直地应力梯度
    vertical_ground_stress_gradient: float
    # 原始液体密度
    original_liquid_density: float
    # 井眼半径
    borehole_radius: float
    # 孔隙度
    void_ratio: float
    # 渗透系数
    osmotic_coefficient: float
    # 杨氏模量
    yang_modulus_elasticity: float
    # 钻井液密度
    drilling_fluid_density: float

# 仪器串参数
class  InstrumentStringParams(BaseModel):
    # 仪器个数
    num: int
    # 有效长度 单位m
    l1: float
    # 外径 单位mm
    d1: float
    # 重量 单位kg
    m1: float

class ReqSoftParams(BaseModel):
    # 井号
    wellId: str
    # 插值长度 单位m
    space: float
    # 是否存在造斜点
    is_slanting_point: bool
    # 计算间距  单位m
    calculate_space: float
    # 工具长度 单位m
    L1: float
    # 测井工具外径 单位m
    d1: float
    # 测井工具在空气中的重量 kg/m
    m1: float
    # 流体密度 kg/m3
    rou_m: float
    # 井下工具的下放速度v  单位m/s
    v_push: float
    # 井下工具的上提速度v 单位m/s
    v_pull: float
    # 液体的动力粘度 单位s
    tao_s: float
    # 工具摩擦系数
    mu1: float
    # 电缆外径 单位m
    d2: float
    # 电缆在空气中的重量 单位kg/m
    m2: float
    # 电缆摩擦系数
    mu2: float
    # 拉断力 单位kN
    F_break: float
    # 张力计算参数  单位N
    F_weak_high: float
    F_weak_low: float
    F_weak_rate_low: float
    # 裸眼段内径Doh 单位m
    d_oh: float
    # 裸眼段的深度L_OH 单位m
    L_oh: float
    # 套管列表
    casings: List[CasingParams]
    # 仪器串列表
    instruments: List[InstrumentStringParams]
    # 仪器串第一最大直径 单位m
    d_max1: float
    # 仪器串第二最大直径 单位m
    d_max2: float
    # # 电缆的弹性模量 --> input
    # E2: float
    # 输入的井斜角 单位度
    inclination: float
    # 置信度
    confidence_level: float
    # 安全操作拉力百分比
    operatingLoad: float
    # ************************
    stability: List[StabilityParams]
    # ************************
    # 是否添加液体阻力
    add_liquid_resistance: bool
    # 电缆的残余伸量  m/km/5kN
    cable_stretch: float
    # 是不是公制单位
    is_Not_metric: bool
    # 井口摩擦力 单位N
    wellhead_friction: float
    # 大气压力 单位Pa
    P_atm: float
    # 流量体积 单位m³/min
    Q_min: float
    # 偏心度 默认0 区间为0---1
    skewness: float
    # 是不是光滑壁面 默认是true 光滑壁面
    is_smooth_surface: bool
    # 绝对粗糙度 单位m 默认0.00015m
    absolute_roughness: float





    def calc_md5(self):
        # 将类中数据项的值连接成一个字符串
        data_string = f"{self.wellId}{self.space}{self.calculate_space}{self.add_liquid_resistance}{self.L1}{self.d1}{self.d2}{self.m1}{self.rou_m}{self.v_push}{self.v_pull}{self.tao_s}{self.mu1}{self.d2}" \
                      f"{self.m2}{self.mu2}{self.F_break}{self.F_weak_low}{self.F_weak_high}{self.F_weak_rate_low}{self.L_oh}{self.confidence_level}{self.operatingLoad}{self.cable_stretch}{self.wellhead_friction}" \
                      f"{self.P_atm}{self.Q_min}{self.skewness}{self.is_smooth_surface}{self.absolute_roughness}"
        # 计算 MD5 哈希
        md5_hash = hashlib.md5(data_string.encode()).hexdigest()

        return md5_hash



# 测井仪器截面积
def get_instrument_area(params) -> float:
    return math.pi * 0.25 * math.pow(params.d1, 2)


# 测井仪器的单位密度
def get_instrument_uint_density(params) -> float:
    return params.m1 / get_instrument_area(params)


# 测井仪器的单位浮重
def get_instrument_unit_weight(params) -> float:
    return (get_instrument_uint_density(params) - params.rou_m) * get_instrument_area(params) * 9.81


# 电缆截面面积
def get_cable_area(params) -> float:
    return math.pi * 0.25 * math.pow(params.d2, 2)


# 电缆的单位密度
def get_cable_uint_density(params) -> float:
    return params.m2 / get_cable_area(params)


# 电缆的单位浮重
def get_cable_unit_weight(params) -> float:
    return (get_cable_uint_density(params) - params.rou_m) * get_cable_area(params) * 9.81


# 电缆的界面惯性矩
def get_cable_moment_inertia(params) -> float:
    return math.pi * math.pow(params.d2, 4) / 64

# 原始电缆的弹性模量
def get_cable_elastic_modulus(params) -> float:
    return (5000 * 1000) / (params.cable_stretch * get_cable_area(params))

# 修正系数
def get_correction_factor(params) -> float:
    k: float = 0.75 + 0.0001 * params.rou_m
    return k

# 修正的电缆弹性模量
def get_corrected_cable_elastic_modulus(params) -> float:
    return get_correction_factor(params) * get_cable_elastic_modulus(params)


# 马氏漏斗粘度转换
def get_conversion_viscosity(params) -> float:
    factor_a: float = math.pow(10, -3)
    factor_b: float = math.log((params.tao_s-24.5)/0.58)/1.2
    factor_c: float = math.log(params.rou_m * factor_a)
    viscosity: float = factor_a * math.pow(math.e, factor_b + factor_c)
    return viscosity



# 计算所需参数 -> 根据基础参数可以计算出来的结果
class SoftParams:
    # 井
    wellId: str
    # 间距
    space: float
    # 是否存在造斜点
    is_slanting_point: bool
    # 计算间距
    calculate_space: float
    # 工具长度 单位m
    L1: float
    # 测井工具外径 d1 单位m
    d1: float
    # 测井工具在空气中的重量 kg/m
    m1: float
    # 流体密度 单位kg/m³
    rou_m: float
    # 井下工具的下放速度v 单位m/s
    v_push: float
    # 井下工具的上提速度v 单位m/s
    v_pull: float
    # 液体的动力粘度 单位s
    tao_s: float

    # 裸眼段上提摩擦系数
    mu1: float
    # 电缆外径 单位m
    d2: float
    # 电缆在空气中的重量 单位kg/m
    m2: float
    # 裸眼段下放摩擦系数
    mu2: float
    # 拉断力 单位kN
    F_break: float
    # 张力计算参数    单位N
    F_weak_high: float
    F_weak_low: float
    F_weak_rate_low: float

    # 裸眼段内径Doh 单位m
    d_oh: float
    # 裸眼段的深度L_OH 单位m
    L_oh: float
    # 套管列表
    casings: List[CasingParams]
    # 仪器串列表
    instruments: List[InstrumentStringParams]
    # 仪器串第一最大直径 d_max1 单位m
    d_max1: float
    # 仪器串第二最大直径  d_max2 单位m
    d_max2: float
    # # 电缆的弹性模量
    # E2: float
    # 输入的井斜角 单位度
    inclination: float
    # 置信度
    confidence_level: float
    # 安全操作拉力百分比
    operatingLoad: float
    # 电缆的残余伸量 单位m/km/5kN
    cable_stretch: float
    # 大气压力 单位Pa
    P_atm: float
    # 流量体积 单位m³/min
    Q_min: float
    # 偏心度 默认0 区间为0---1
    skewness: float
    # 是不是光滑壁面 默认是true 光滑壁面
    is_smooth_surface: bool
    # 绝对粗糙度 单位m 默认0.00015m
    absolute_roughness: float


    mu_push_dict: {}
    mu_pull_dict: {}
    num_dict: {}
    l1_dict: {}
    d1_dict: {}
    m1_dict: {}
    # 屈曲载荷 根号(a*b) = 根号(a) * 根号(b)
    # f_hel_dict: {}
    # 井斜角
    inc_dict: {}
    # n开套管内径或裸眼段内内径，与井下工具之比
    instrument_rate_dict: {}
    # n开套管内径或裸眼段内内径，与电缆直径之比
    cable_rate_dict: {}


    def get_inc(self,depth: int):
        inc: float = self.inc_dict.get(depth)
        return inc


    # def get_f_hel(self, depth):
    #     f_hel: float = self.f_hel_dict.get(depth)
    #     return f_hel
    #
    def get_mu_push(self, depth):
        mu: float = self.mu_push_dict.get(depth)
        if mu is None:
            # 空就是返回裸眼段摩擦系数
            return self.mu2
        else:
            return mu

    def get_mu_pull(self, depth: float):
        mu: float = self.mu_pull_dict.get(depth)
        if mu is None:
            # 空就是返回裸眼段摩擦系数
            return self.mu1
        else:
            return mu


    def get_instrument_rate(self, depth: float):
        # instrument_rate: float = self.instrument_rate_dict.get(depth)
        # if instrument_rate is None:
        #     return self.d_oh / self.d1
        # else:
        #     return instrument_rate
        return self.d_oh / self.d1

    def get_cable_rate(self, depth: float):
        # cable_rate: float = self.cable_rate_dict.get(depth)
        # if cable_rate is None:
        #     return self.d_oh / self.d2
        # else:
        #     return cable_rate
        return self.d_oh / self.d2




    def __init__(self, params: ReqSoftParams):
        if params is None:
            print("入参为None")
        else:
            self.wellId = params.wellId
            self.space = params.space
            self.is_slanting_point = params.is_slanting_point
            self.calculate_space = params.calculate_space
            self.L1 = params.L1
            self.d1 = params.d1
            self.m1 = params.m1
            self.rou_m = params.rou_m
            self.mu1 = params.mu1
            self.v_push = params.v_push
            self.v_pull = params.v_pull
            self.tao_s = params.tao_s
            self.tao_p = get_conversion_viscosity(params)
            self.d2 = params.d2
            self.m2 = params.m2
            self.mu2 = params.mu2
            self.F_break = params.F_break
            self.F_weak_high = params.F_weak_high
            self.F_weak_low = params.F_weak_low
            self.F_weak_rate_low = params.F_weak_rate_low
            self.d_oh = params.d_oh
            self.L_oh = params.L_oh
            self.casings = params.casings
            self.instruments = params.instruments
            self.d_max1 = params.d_max1
            self.d_max2 = params.d_max2
            self.E2 = get_corrected_cable_elastic_modulus(params)
            self.inclination = params.inclination
            self.confidence_level = params.confidence_level
            self.operatingLoad = params.operatingLoad
            # self.w1 = get_instrument_unit_weight(params)

            self.w2 = get_cable_unit_weight(params)
            self.I2 = get_cable_moment_inertia(params)
            # self.A1 = get_instrument_area(params)
            self.A2 = get_cable_area(params)
            # ******************************
            self.stability = params.stability
            # ******************************
            self.add_liquid_resistance = params.add_liquid_resistance
            self.cable_stretch = params.cable_stretch
            self.is_Not_metric = params.is_Not_metric
            self.wellhead_friction = params.wellhead_friction
            self.P_atm = params.P_atm
            self.Q_min = params.Q_min
            self.skewness = params.skewness
            self.is_smooth_surface = params.is_smooth_surface
            self.absolute_roughness = params.absolute_roughness

            t_mu_push_dict: Dict = {}
            t_mu_pull_dict: Dict = {}
            # t_instrument_rate_dict: Dict = {}
            # t_cable_rate_dict: Dict = {}
            for casing in params.casings:
                for i in range(int(casing.start),int(casing.end) + 1):
                    t_mu_pull_dict[i] = casing.mu_pull
                    t_mu_push_dict[i] = casing.mu_push
                    # t_instrument_rate_dict[i] = casing.d / self.d1
                    # t_cable_rate_dict[i] = casing.d / self.d2


            self.mu_pull_dict = t_mu_pull_dict
            self.mu_push_dict = t_mu_push_dict
            # self.instrument_rate_dict = t_instrument_rate_dict
            # self.cable_rate_dict = t_cable_rate_dict

            t_l1_dict: Dict = {}
            t_m1_dict: Dict = {}
            t_d1_dict: Dict = {}
            t_num_dict: Dict = {}
            t_area_dict: Dict = {}
            t_density_dict: Dict = {}
            t_weight_dict: Dict = {}
            total_area = 0.0
            total_weight = 0.0

            index = 0  # 统一索引，确保不会因 num 计算问题导致错误
            sum_instruments_length = 0.0
            for instruments in params.instruments:
                sum_instruments_length += instruments.l1

            for instruments in params.instruments:
                t_l1_dict[index] = instruments.l1
                t_m1_dict[index] = instruments.m1
                t_d1_dict[index] = instruments.d1 * 0.001
                t_num_dict[index] = instruments.num
                percentage = instruments.l1 / sum_instruments_length
                t_area_dict[index] = math.pi * 0.25 * math.pow(t_d1_dict[index], 2) * percentage
                # 判断 t_m1_dict[i] 是否为 0
                # if t_m1_dict[i] == 0:
                #     t_weight_dict[i] = 0  # 如果 t_m1_dict[i] 为 0，则 t_weight_dict[i] 直接设为 0
                # else:
                #     t_density_dict[i] = t_m1_dict[i] / t_area_dict[i]
                #     t_weight_dict[i] = (t_density_dict[i] - self.rou_m) * t_area_dict[i] * 9.81
                total_area += t_area_dict[index]
                # total_weight += t_weight_dict[i]

                index += 1  # 递增索引，防止键冲突

            self.l1_dict = t_l1_dict
            self.m1_dict = t_m1_dict
            self.d1_dict = t_d1_dict
            self.num_dict = t_num_dict
            self.area_dict = t_area_dict
            self.density_dict = t_density_dict
            self.weight_dict = t_weight_dict
            self.total_area = total_area
            # self.total_weight = total_weight
            # self.w1 = get_instrument_unit_weight(params)
            total_weight = (params.m1 / total_area - self.rou_m) * total_area * 9.81
            self.w1 = total_weight
            self.A1 = total_area


    def buildByPassParams(self, params):
        self.space = params.space
        self.calculate_space = params.calculate_space
        self.L1 = round(params.L1)
        self.is_slanting_point = params.is_slanting_point
        self.d1 = params.d1
        self.m1 = params.m1
        self.rou_m = params.rou_m
        self.mu1 = params.mu1
        self.d2 = params.d2
        self.m2 = params.m2
        self.mu2 = params.mu2
        self.F_break = params.F_break
        self.F_weak_high = params.F_weak_high
        self.F_weak_low = params.F_weak_low
        self.F_weak_rate_low = params.F_weak_rate_low
        self.d_oh = params.d_oh
        self.L_oh = params.L_oh
        self.casings = params.casings
        self.instruments = params.instruments
        self.d_max1 = params.d_max1
        self.d_max2 = params.d_max2
        self.E2 = get_corrected_cable_elastic_modulus(params)
        self.inclination = params.inclination
        self.confidence_level = params.confidence_level

        self.operatingLoad = params.operatingLoad
        # self.w1 = get_instrument_unit_weight(params)
        self.w2 = get_cable_unit_weight(params)
        self.I2 = get_cable_moment_inertia(params)
        # self.A1 = get_instrument_area(params)
        self.A2 = get_cable_area(params)
        self.v_push = params.v_push
        self.v_pull = params.v_pull
        self.tao_s = params.tao_s
        self.tao_p = get_conversion_viscosity(params)
        t_mu_push_dict: Dict = {}
        t_mu_pull_dict: Dict = {}
        # t_instrument_rate_dict: Dict = {}
        # t_cable_rate_dict: Dict = {}
        for casing in params.casings:
            for i in range(int(casing.start), int(casing.end)):
                t_mu_pull_dict[i] = casing.mu_pull
                t_mu_push_dict[i] = casing.mu_push
                # t_instrument_rate_dict[i] = casing.d / self.d1
                # t_cable_rate_dict[i] = casing.d / self.d2


        self.mu_pull_dict = t_mu_pull_dict
        self.mu_push_dict = t_mu_push_dict

        t_l1_dict: Dict = {}
        t_m1_dict: Dict = {}
        t_d1_dict: Dict = {}
        t_num_dict: Dict = {}
        t_area_dict: Dict = {}
        t_density_dict: Dict = {}
        t_weight_dict: Dict = {}
        total_area = 0.0
        total_weight = 0.0
        # index = 0  # 统一索引，确保不会因 num 计算问题导致错误

        # for instruments in params.instruments:

        #     for i in range(int(instruments.num)):
        #         t_l1_dict[i] = instruments.l1
        #         t_m1_dict[i] = instruments.m1
        #         t_d1_dict[i] = instruments.d1
        #         t_num_dict[i] = instruments.num
        #         t_area_dict[i] = math.pi * 0.25 * math.pow(t_d1_dict[i], 2)
        #         # 判断 t_m1_dict[i] 是否为 0
        #         if t_m1_dict[i] == 0:
        #             t_weight_dict[i] = 0  # 如果 t_m1_dict[i] 为 0，则 t_weight_dict[i] 直接设为 0
        #         else:
        #             t_density_dict[i] = t_m1_dict[i] / t_area_dict[i]
        #             t_weight_dict[i] = (t_density_dict[i] - self.rou_m) * t_area_dict[i] * 9.81
        #         total_area += t_area_dict[i]
        #         total_weight += t_weight_dict[i]

        #         index += 1  # 递增索引，防止键冲突
        # self.l1_dict = t_l1_dict
        # self.m1_dict = t_m1_dict
        # self.d1_dict = t_d1_dict
        # self.num_dict = t_num_dict
        # self.w1 = total_weight
        # self.A1 = total_area
        index = 0  # 统一索引，确保不会因 num 计算问题导致错误
        sum_instruments_length = 0.0
        for instruments in params.instruments:
            sum_instruments_length += instruments.l1
        for instruments in params.instruments:
            t_l1_dict[index] = instruments.l1
            t_m1_dict[index] = instruments.m1
            t_d1_dict[index] = instruments.d1 * 0.001
            t_num_dict[index] = instruments.num
            percentage = instruments.l1 / sum_instruments_length
            t_area_dict[index] = math.pi * 0.25 * math.pow(t_d1_dict[index], 2) * percentage
            total_area += t_area_dict[index]
            index += 1  # 递增索引，防止键冲突
            self.l1_dict = t_l1_dict
            self.m1_dict = t_m1_dict
            self.d1_dict = t_d1_dict
            self.num_dict = t_num_dict
            self.area_dict = t_area_dict
            self.density_dict = t_density_dict
            self.weight_dict = t_weight_dict
            self.total_area = total_area
            total_weight = (params.m1 / total_area - self.rou_m) * total_area * 9.81
            self.w1 = total_weight
            self.A1 = total_area



        # self.instrument_rate_dict = t_instrument_rate_dict
        # self.cable_rate_dict = t_cable_rate_dict
        # return self
        # *****************************
        self.stability = params.stability
        self.add_liquid_resistance = params.add_liquid_resistance
        self.cable_stretch = params.cable_stretch
        self.is_Not_metric = params.is_Not_metric
        self.wellhead_friction = params.wellhead_friction
        self.P_atm = params.P_atm
        self.Q_min = params.Q_min
        self.skewness = params.skewness
        self.is_smooth_surface = params.is_smooth_surface
        self.absolute_roughness = params.absolute_roughness

